package com.hs.sentinelr.controller;

import com.baomidou.mybatisplus.extension.api.R;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁测试
 *
 * @Author lingNan
 * @Date 2021/8/21 3:20 下午
 **/
@RequestMapping("order")
@RestController
public class OrderController {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/deductStick")
    public R deductStick() {
        String stockKey = "stock";
        int stock = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(stockKey)));
        if (stock > 0) {
            int realStock = stock - 1;
            stringRedisTemplate.opsForValue().set(stockKey, String.valueOf(realStock));
            System.out.println("扣减成功，剩余库存: " + realStock);
        } else {
            System.out.println("扣减失败，库存不足");
        }
        return R.ok("end");
    }

    /**
     * 手动锁
     *
     * @return
     */
    @GetMapping("/deductStick2")
    public R deductStick2() {
        String stockKey = "stock2";
        String producet001 = "producet001";
        //获取锁并设置超时时间
        //设置uuid解锁时判断是否时当前线程的锁
        String uuid = UUID.randomUUID().toString();
        //原子操作
        Boolean lockStatus = stringRedisTemplate.opsForValue().setIfAbsent(producet001, uuid, 30, TimeUnit.SECONDS);
        if (!lockStatus) {
            return R.failed("获取锁失败!");
        }
        try {
            int stock = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(stockKey)));
            if (stock > 0) {
                int realStock = stock - 1;
                stringRedisTemplate.opsForValue().set(stockKey, String.valueOf(realStock));
                System.out.println("扣减成功，剩余库存: " + realStock);
            } else {
                System.out.println("扣减失败，库存不足");
            }
        } finally {
            //释放锁
            if (stringRedisTemplate.opsForValue().get(producet001).equals(uuid)) {
                stringRedisTemplate.delete(producet001);
            }
        }

        return R.ok("end");
    }

    /**
     * redisson锁
     *
     * @return
     */
    @GetMapping("/deductStick3")
    public R deductStick3() {
        String stockKey = "stock3";
        String producet001 = "producet001";
        //获取锁并设置超时时间
        RLock lock = redissonClient.getLock(producet001);
        //原子操作
        try {
            lock.lock();
            int stock = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(stockKey)));
            if (stock > 0) {
                int realStock = stock - 1;
                stringRedisTemplate.opsForValue().set(stockKey, String.valueOf(realStock));
                System.out.println("扣减成功，剩余库存: " + realStock);
            } else {
                System.out.println("扣减失败，库存不足");
            }
        } finally {
            //释放锁
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return R.ok("end");
    }

    /**
     * redisson tryLock锁
     *
     * @return
     */
    @GetMapping("/deductStick4")
    public R deductStick4(Integer waitTime,Integer leaseTime) {
        String stockKey = "stock4";
        String producet001 = "producet002";
        //获取锁并设置超时时间
        RLock lock = redissonClient.getLock(producet001);
        //原子操作
        try {
            lock.tryLock(waitTime,leaseTime,TimeUnit.SECONDS);
            int stock = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(stockKey)));
            if (stock > 0) {
                int realStock = stock - 1;
                stringRedisTemplate.opsForValue().set(stockKey, String.valueOf(realStock));
                System.out.println("扣减成功，剩余库存: " + realStock);
            } else {
                System.out.println("扣减失败，库存不足");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放锁
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return R.ok("end");
    }

    @GetMapping("hyperLogLog")
    public void hyperLogLogTest(){
        String key = "COUNT:USER";
        stringRedisTemplate.delete(key);
        int count = 100000;
        List<String> users = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            users.add("user" + i);
        }
        stringRedisTemplate.opsForHyperLogLog().add(key,users.toArray(new String[count]));
        System.out.println(stringRedisTemplate.opsForHyperLogLog().size(key));
    }

    @GetMapping("bloomInit")
    public void bloomInitTest(){
        String key = "bloom:user";
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(key);
        bloomFilter.tryInit(100000,0.03);
        for (int i = 0; i < 100000; i++) {
            bloomFilter.add("user" + i);
        }
        System.out.println(bloomFilter.getExpectedInsertions());
        System.out.println(bloomFilter.getFalseProbability());
        System.out.println(bloomFilter.count());
    }

    @GetMapping("bloomGet")
    public R<Boolean> bloomGetTest(String name){
        String key = "bloom:user";
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(key);
        return R.ok(bloomFilter.contains(name));
    }

}
